<script setup lang="ts">
import ExpressionIndicatorsTable from './ExpressionIndicatorsTable.vue'
import IndicatorMethodPickerDialog from './IndicatorMethodPickerDialog.vue'
import IndicatorPickerDialog from './IndicatorPickerDialog.vue'

import { useStatisticalIndicators } from '@/mixins/StatisticalIndicators/MixinStatisticalIndicators'

import type {
  IndicatorMethod,
  StatisticalIndicator,
} from '@/types/modules/statistical-indicator'

import { checkExpression as _checkExpression } from '@/api/modules/expression-checking'

defineProps<{
  type: 1 | 2
}>()
const emits = defineEmits<{
  (e: 'blur', value: string): void
  (e: 'change', value: string): void
}>()

const error = defineModel<boolean>('error')
const expression = defineModel<string>({ required: true })
const inputRef = ref<HTMLTextAreaElement>()
const indicatorMethodPickerDialogRef
  = ref<InstanceType<typeof IndicatorMethodPickerDialog>>()
const indicatorPickerDialogRef
  = ref<InstanceType<typeof IndicatorPickerDialog>>()

const {
  lists: selectedIndicators,
  resolveIndicatorsByExpression,
} = useStatisticalIndicators()

function handleSelectedIndicatorMethod(
  row: IndicatorMethod,
) {
  insertText(row.method)
}

function handleSelectedIndicators(
  row: StatisticalIndicator,
) {
  insertText(row.indicatorNumber)
}

function clickPickIndicatorButton() {
  indicatorPickerDialogRef.value?.open()
}
function clickPickMethodButton() {
  indicatorMethodPickerDialogRef.value?.open()
}

function handleClickSymbol(symbol: string) {
  insertText(symbol)
}

function insertText(target: string, pos?: number) {
  if (inputRef.value) {
    pos = pos ?? inputRef.value.selectionStart
    const txt = unref(expression)
    const str = target
    const newText
      = txt.substring(0, pos) + str + txt.substring(pos)
    expression.value = newText
    inputRef.value.focus()
    nextTick(() => {
      inputRef.value?.setSelectionRange(
        pos ?? 0,
        (pos ?? 0) + str.length,
      )
    })
  }
}

async function handleBlur() {
  const t = unref(expression)
  if (t !== '') {
    // 解析公式中的指标
    resolveIndicatorsByExpression(t)
  }
  emits('blur', t)
}

// 表达式改变后（失去焦点后触发），解析公式中的指标
function handleChange() {
  const t = unref(expression)
  emits('change', t)
}

async function checkExpression() {
  const t = unref(expression)
  try {
    const { data, message } = await _checkExpression(t)
    // const { data, message } = {
    //   message:
    //     '1.函数convertToNum参数输入错误\n2.运算符无法解析\n',
    //   data: false
    // };
    if (data) {
      ElMessage.success('校验成功')
    }
    else {
      ElMessageBox.alert(
        () =>
          h(
            'div',
            { style: 'white-space: pre-wrap;' },
            message || '',
          ),
        '校验失败',
      )
    }
  }
  catch (e) {}
}

// 外部调用校验必填
function validate(msg: string) {
  const t = unref(expression)
  const isValid = t !== ''
  if (!isValid) {
    inputRef.value?.scrollIntoView({
      behavior: 'smooth',
    })
    ElMessage.warning(msg)
  }
  error.value = !isValid
  return isValid
}

// 实时（input）校验非空
watch(
  () => unref(expression),
  (t: string) => {
    error.value = t === ''
  },
)

onMounted(() => {
  // 挂载后解析一次表达式
  const t = unref(expression)
  if (t !== '') {
    resolveIndicatorsByExpression(t)
  }
})

defineExpose({
  validate,
})
</script>

<template>
  <div class="expression-picker">
    <div class="width-fill flex">
      <div class="flex-fillRemaining exp-input">
        <div class="exp-title">
          公式
        </div>
        <textarea
          ref="inputRef"
          v-model.trim="expression"
          placeholder="请输入..."
          class="width-fill exp-area block border rounded-sm"
          :class="{ 'has-error': error }"
          :rows="8"
          @blur="handleBlur"
          @change="handleChange"
        />
        <div
          class="margin-top-xs align-center exp-operate-symbols flex justify-between"
        >
          <ElButton
            type="primary"
            plain
            @click="handleClickSymbol('+')"
          >
            +
          </ElButton>
          <ElButton
            type="primary"
            plain
            @click="handleClickSymbol('-')"
          >
            -
          </ElButton>
          <ElButton
            type="primary"
            plain
            @click="handleClickSymbol('*')"
          >
            *
          </ElButton>
          <ElButton
            type="primary"
            plain
            @click="handleClickSymbol('/')"
          >
            /
          </ElButton>
          <ElButton
            type="primary"
            plain
            @click="handleClickSymbol('(')"
          >
            (
          </ElButton>
          <ElButton
            type="primary"
            plain
            @click="handleClickSymbol(')')"
          >
            )
          </ElButton>
          <ElButton
            type="primary"
            plain
            @click="clickPickMethodButton"
          >
            函数列表
          </ElButton>
          <ElButton
            type="primary"
            plain
            @click="clickPickIndicatorButton"
          >
            指标列表
          </ElButton>
          <ElButton
            type="primary"
            plain
            @click="checkExpression"
          >
            校验
          </ElButton>
        </div>
      </div>
      <div
        class="flex-fillRemaining margin-left-sm overflow exp-indicators"
      >
        <div class="exp-title">
          公式中使用的指标
        </div>
        <ExpressionIndicatorsTable
          :data="selectedIndicators"
        />
      </div>
    </div>

    <!-- 选择指标弹框 -->
    <IndicatorPickerDialog
      ref="indicatorPickerDialogRef"
      @selected="handleSelectedIndicators"
    />
    <!-- 选择函数弹框 -->
    <IndicatorMethodPickerDialog
      ref="indicatorMethodPickerDialogRef"
      :type="type"
      @selected="handleSelectedIndicatorMethod"
    />
  </div>
</template>

<style lang="scss" scoped>
.exp-title {
  margin-bottom: 12px;
}
.exp-area {
  box-sizing: border-box;
  padding: 10px;
  outline: none;
  resize: none;
  white-space: pre-wrap;
  font-family: 'Courier New', Courier, monospace;
  background: transparent;
  &:not(.has-error):focus {
    border-color: var(--el-color-primary);
  }
  &.has-error {
    border-color: var(--el-color-danger);
  }
}
.exp-operate-symbols {
  :deep(.el-button) {
    padding-left: 10px;
    padding-right: 10px;
    & + .el-button {
      margin-left: 10px;
    }
  }
}
</style>
